package com.example.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.dos.AwardDO;
import com.example.dto.AwardDTO;
import com.example.dto.AwardExportDTO;
import com.example.dto.AwardImportDTO;
import com.example.exception.BusinessException;
import com.example.mapper.AwardMapper;
import com.example.service.impl.AwardServiceImpl;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

/**
 * <p>
 *   获奖信息服务层实现类单元测试
 * </p>
 * @author 34448
 */
public class AwardServiceImplTest {

    @Mock
    private AwardMapper awardMapper;

    @InjectMocks
    private AwardServiceImpl awardService;

    @BeforeEach
    void setUp() {
        MockitoAnnotations.openMocks(this);
    }

    @Test
    void testAddAward_Success() throws IOException {
        AwardDTO awardDTO = new AwardDTO();
        awardDTO.setAwardName("Test Award");
        awardDTO.setAwardDate(new Date());
        awardDTO.setCompetitionName("Test Competition");
        awardDTO.setTeacherId(1);
        awardDTO.setTeamMembers("Member1, Member2");
        awardDTO.setStudentIds("1, 2, 3");
        awardDTO.setCertificateUrl("http://example.com/certificate");

        when(awardMapper.selectOne(any(QueryWrapper.class))).thenReturn(null);
        when(awardMapper.insert(any(AwardDO.class))).thenReturn(1);

        assertTrue(awardService.addAward(awardDTO));
    }

    @Test
    void testAddAward_Failure() {
        AwardDTO awardDTO = new AwardDTO();
        awardDTO.setAwardName("Test Award");
        awardDTO.setAwardDate(new Date());
        awardDTO.setCompetitionName("Test Competition");
        awardDTO.setTeacherId(1);
        awardDTO.setTeamMembers("Member1, Member2");
        awardDTO.setStudentIds("1, 2, 3");
        awardDTO.setCertificateUrl("http://example.com/certificate");

        AwardDO existingAward = new AwardDO();
        existingAward.setAwardName(awardDTO.getAwardName());
        existingAward.setAwardDate(awardDTO.getAwardDate());
        existingAward.setCompetitionName(awardDTO.getCompetitionName());
        existingAward.setTeacherId(awardDTO.getTeacherId());
        existingAward.setTeamMembers(awardDTO.getTeamMembers());
        existingAward.setStudentIds(awardDTO.getStudentIds());
        existingAward.setCertificateUrl(awardDTO.getCertificateUrl());

        when(awardMapper.selectOne(any(QueryWrapper.class))).thenReturn(existingAward);

        assertThrows(BusinessException.class, () -> awardService.addAward(awardDTO));
    }

    @Test
    void testDeleteAward_Success() {
        Integer awardId = 1;
        AwardDO existingAward = new AwardDO();
        existingAward.setAwardId(awardId);

        when(awardMapper.selectById(awardId)).thenReturn(existingAward);
        when(awardMapper.deleteById(awardId)).thenReturn(1);

        assertTrue(awardService.deleteAward(awardId));
    }

    @Test
    void testDeleteAward_Failure() {
        Integer awardId = 1;

        when(awardMapper.selectById(awardId)).thenReturn(null);

        assertThrows(BusinessException.class, () -> awardService.deleteAward(awardId));
    }

    @Test
    void testUpdateAward_Success() {
        Integer awardId = 1;
        AwardDTO awardDTO = new AwardDTO();
        awardDTO.setAwardId(awardId);
        awardDTO.setAwardName("Updated Award");
        awardDTO.setAwardDate(new Date());
        awardDTO.setCompetitionName("Updated Competition");
        awardDTO.setTeacherId(2);
        awardDTO.setTeamMembers("Updated Member1, Updated Member2");
        awardDTO.setStudentIds("4, 5, 6");
        awardDTO.setCertificateUrl("http://example.com/updated-certificate");

        AwardDO existingAward = new AwardDO();
        existingAward.setAwardId(awardId);

        when(awardMapper.selectById(awardId)).thenReturn(existingAward);
        when(awardMapper.updateById(any(AwardDO.class))).thenReturn(1);

        assertTrue(awardService.updateAward(awardDTO));
    }

    @Test
    void testUpdateAward_Failure() {
        Integer awardId = 1;
        AwardDTO awardDTO = new AwardDTO();
        awardDTO.setAwardId(awardId);

        when(awardMapper.selectById(awardId)).thenReturn(null);

        assertThrows(BusinessException.class, () -> awardService.updateAward(awardDTO));
    }

    @Test
    void testGetAwards() {
        Integer awardId = 1;
        List<AwardDO> awards = new ArrayList<>();
        AwardDO awardDO = new AwardDO();
        awardDO.setAwardId(awardId);
        awards.add(awardDO);

        when(awardMapper.selectList(any(QueryWrapper.class))).thenReturn(awards);

        assertEquals(awards, awardService.getAwards(awardId));
    }

    @Test
    void testImportAwards_Success() throws IOException {
        String filePath = "src/test/resources/test_import.csv";
        Path path = Paths.get(filePath);
        Files.write(path, "Test Award,2023-10-01,Test Competition,1,Member1,Member2,http://example.com/certificate\n".getBytes());

        AwardImportDTO awardImportDTO = new AwardImportDTO();
        awardImportDTO.setFilePath(filePath);

        List<AwardDO> awards = new ArrayList<>();
        AwardDO awardDO = new AwardDO();
        awardDO.setAwardName("Test Award");
        awardDO.setAwardDate(Date.valueOf("2023-10-01"));
        awardDO.setCompetitionName("Test Competition");
        awardDO.setTeacherId(1);
        awardDO.setTeamMembers("Member1,Member2");
        awardDO.setStudentIds("1,2,3");
        awardDO.setCertificateUrl("http://example.com/certificate");
        awards.add(awardDO);

        when(awardMapper.insertBatchSomeColumn(any(List.class))).thenReturn(1);

        assertTrue(awardService.importAwards(awardImportDTO));
    }

    @Test
    void testImportAwards_FileNotFound() {
        AwardImportDTO awardImportDTO = new AwardImportDTO();
        awardImportDTO.setFilePath("nonexistent_file.csv");

        assertThrows(BusinessException.class, () -> awardService.importAwards(awardImportDTO));
    }

    @Test
    void testExportAwards_Success() throws IOException {
        String filePath = "src/test/resources/test_export.csv";
        AwardExportDTO awardExportDTO = new AwardExportDTO();
        awardExportDTO.setFilePath(filePath);

        List<AwardDO> awards = new ArrayList<>();
        AwardDO awardDO = new AwardDO();
        awardDO.setAwardName("Test Award");
        awardDO.setAwardDate(Date.valueOf("2023-10-01"));
        awardDO.setCompetitionName("Test Competition");
        awardDO.setTeacherId(1);
        awardDO.setTeamMembers("Member1,Member2");
        awardDO.setStudentIds("1,2,3");
        awardDO.setCertificateUrl("http://example.com/certificate");
        awards.add(awardDO);

        when(awardMapper.selectList(any(QueryWrapper.class))).thenReturn(awards);

        assertTrue(awardService.exportAwards(awardExportDTO));
    }

    @Test
    void testExportAwards_Failure() throws IOException {
        String filePath = "src/test/resources/test_export.csv";
        AwardExportDTO awardExportDTO = new AwardExportDTO();
        awardExportDTO.setFilePath(filePath);

        doThrow(new IOException("Failed to write file")).when(awardService).exportAwards(awardExportDTO);

        assertThrows(BusinessException.class, () -> awardService.exportAwards(awardExportDTO));
    }
}